package com.alinesno.cloud.initializr.starter.cicd.deploy.k8s.api;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.shiro.util.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import com.alinesno.cloud.initializr.starter.cicd.deploy.k8s.BaseApi;
import com.alinesno.cloud.initializr.starter.cicd.deploy.k8s.bean.DeploymentBean;
import com.alinesno.cloud.initializr.starter.enums.LanguageEnum;
import com.alinesno.cloud.initializr.starter.enums.SceneEnum;
import com.alinesno.cloud.rest.gateway.adapter.utils.StringUtils;

import io.fabric8.kubernetes.api.model.EnvVar;
import io.fabric8.kubernetes.api.model.HostPathVolumeSource;
import io.fabric8.kubernetes.api.model.IntOrString;
import io.fabric8.kubernetes.api.model.Probe;
import io.fabric8.kubernetes.api.model.Quantity;
import io.fabric8.kubernetes.api.model.TCPSocketAction;
import io.fabric8.kubernetes.api.model.Volume;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.fabric8.kubernetes.api.model.apps.DeploymentBuilder;

/**
 * 部署服务
 *
 * @author WeiXiaoJin
 * @date 2021年6月25日 下午9:17:13
 */
@Component
public class DeploymentApi extends BaseApi {

	private static final Logger log = LoggerFactory.getLogger(DeploymentApi.class) ;

	/**
	 * 发布对象
	 * @param bean
	 * @return
	 */
	public Deployment createDeployment(DeploymentBean bean) {

		String namespace = bean.getNamespace() ;
		String name = bean.getName() ;
		int applicationPort = bean.getContainerPort() ;
		String secretName = bean.getPullSecret()  ; 
		String imageName = bean.getImage() ; 
		
		Assert.hasLength(namespace , "命名空间为空.");
		Assert.hasLength(name , "服务名称为空.");
		Assert.isTrue(applicationPort > 0 , "端口不能为空.");
		Assert.hasLength(secretName, "密钥为空.");
		Assert.hasLength(imageName, "镜像为空.");

		Map<String ,Quantity> requestResourceMap = initRequestResource(bean) ; 
		Map<String ,Quantity> limitResourceMap = initLimitResource(bean) ; 

		Map<String , String> kindLabelMap = new HashMap<String , String>() ;
		kindLabelMap.put("app", name) ;

		Map<String , String> templateLabelMap = new HashMap<String , String>() ;
		templateLabelMap.put("app", name) ;

		Volume specVolumeItem = new Volume() ;
		specVolumeItem.setName("timezone");

		HostPathVolumeSource hostPathVolumeSource = new HostPathVolumeSource() ;
		hostPathVolumeSource.setPath("/usr/share/zoneinfo/Asia/Shanghai");

		specVolumeItem.setHostPath(hostPathVolumeSource);

		List<EnvVar> envMap = initEnv() ; 

		// >>>>>>>>>>>>>>>> livenessProbe >>>>>>>>>>>>
		Probe prebe = new Probe() ;

		TCPSocketAction tcpSocketAction = new TCPSocketAction() ;
		IntOrString intOrStringPort = new IntOrString() ;
		intOrStringPort.setIntVal(applicationPort) ;
		tcpSocketAction.setPort(intOrStringPort) ;

		prebe.setTcpSocket(tcpSocketAction) ;
		prebe.setInitialDelaySeconds(60) ;
		prebe.setPeriodSeconds(30) ;
		prebe.setTimeoutSeconds(45) ;

		Deployment deployment = new DeploymentBuilder()

		  .withNewMetadata()
		  .withNamespace(namespace)
		  .addToLabels(kindLabelMap)
		  .withName(name)
		  .endMetadata()

		  .withNewSpec()
		  .withReplicas(bean.getReplicas())

		  // >>>>>>>>>>>>>>>>>>>> template_start >>>>>>>>>>>
		  .withNewTemplate()
		  .withNewMetadata()
		  .addToLabels(templateLabelMap)
		  .endMetadata()

		  .withNewSpec()
		  .addToVolumes(specVolumeItem)
		  .addNewImagePullSecret(secretName)
		  .addNewContainer()
		  .withName(name)
		  .withImage(imageName)
		  
		  // >>>>>>>>>>>>>>>>> resources_start >>>>>>>>>>>>>>>>>>>>>
		  .withNewResources()
		  .withRequests(requestResourceMap)
		  .withLimits(limitResourceMap)
		  .endResources()
		  // >>>>>>>>>>>>>>>>> resources_end >>>>>>>>>>>>>>>>>>>>>

		  .addNewPort()
		  .withProtocol("TCP")
		  .withContainerPort(bean.getContainerPort())
		  .endPort()
		  .withEnv(envMap)

		  // >>>>>>>>>>>>>>>>>>>>> livenessProbe_start >>>>>>>>>>>>>>>>>.
		  .withLivenessProbe(prebe)
		  // >>>>>>>>>>>>>>>>>>>>> livenessProbe_end >>>>>>>>>>>>>>>>>.

		  .withImagePullPolicy("Always")

		  .endContainer()
		  .endSpec()
		  .endTemplate()
		  // >>>>>>>>>>>>>>>>>>>> template_end >>>>>>>>>>>

		  .withReplicas(bean.getReplicas())
		  .withRevisionHistoryLimit(10)
		  .withNewSelector()
		  .addToMatchLabels("app", name)
		  .endSelector()
		  
		  .endSpec()
		  .build();


		deployment = client().apps().deployments().inNamespace(namespace).create(deployment);
		log.info("Created deployment: {}", deployment);
		
		return deployment ;
	}

	/**
	 * 获取限制资源
	 * @param bean
	 * @return
	 */
	private Map<String, Quantity> initLimitResource(DeploymentBean bean) {
		
		Map<String , Quantity> map = new HashMap<String , Quantity>() ; 
	
		if(StringUtils.isNotEmpty(bean.getResourceLimitCpu())) {
			Quantity q = new Quantity() ; 
			q.setAmount(bean.getResourceLimitCpu());
			map.put("cpu", q) ; 
		} else {
			Quantity q = new Quantity() ; 
			if(LanguageEnum.JAVA.name().equals(bean.getLanguage())) {  // Java语言
				if(bean.getScene().equals(SceneEnum.DEV.name())) {  // 开发环境 
					q.setAmount("10m");
				} else if(bean.getScene().equals(SceneEnum.NORMAL.name())) {  // 通用环境 
					q.setAmount("50m");
				} else if(bean.getScene().equals(SceneEnum.PRO.name())) {  // 生产环境 
					q.setAmount("100m");
				}
			}
			map.put("cpu", q) ; 
		}
		
		if(StringUtils.isNotEmpty(bean.getResourceLimitMem())) {
			Quantity q = new Quantity() ; 
			q.setAmount(bean.getResourceLimitMem());
			map.put("memory", q) ; 
		} else {
			Quantity q = new Quantity() ; 
			if(LanguageEnum.JAVA.name().equals(bean.getLanguage())) {  // Java语言
				if(bean.getScene().equals(SceneEnum.DEV.name())) {  // 开发环境 
					q.setAmount("512Mi");
				} else if(bean.getScene().equals(SceneEnum.NORMAL.name())) {  // 通用环境 
					q.setAmount("1024Mi");
				} else if(bean.getScene().equals(SceneEnum.PRO.name())) {  // 生产环境 
					q.setAmount("4096Mi");
				}
			}
			map.put("memory", q) ; 
		}
		
		return map ;
	}

	/**
	 * 获取初始化资源
	 * @param bean
	 * @return
	 */
	private Map<String, Quantity> initRequestResource(DeploymentBean bean) {
		
		Map<String , Quantity> map = new HashMap<String , Quantity>() ; 
	
		if(StringUtils.isNotEmpty(bean.getResourceLimitCpu())) {
			Quantity q = new Quantity() ; 
			q.setAmount(bean.getResourceLimitCpu());
			map.put("cpu", q) ; 
		} else {
			Quantity q = new Quantity() ; 
			if(LanguageEnum.JAVA.name().equals(bean.getLanguage())) {  // Java语言
				if(bean.getScene().equals(SceneEnum.DEV.name())) {  // 开发环境 
					q.setAmount("5m");
				} else if(bean.getScene().equals(SceneEnum.NORMAL.name())) {  // 通用环境 
					q.setAmount("10m");
				} else if(bean.getScene().equals(SceneEnum.PRO.name())) {  // 生产环境 
					q.setAmount("20m");
				}
			}
			map.put("cpu", q) ; 
		}
		
		if(StringUtils.isNotEmpty(bean.getResourceLimitMem())) {
			Quantity q = new Quantity() ; 
			q.setAmount(bean.getResourceLimitMem());
			map.put("memory", q) ; 
		} else {
			Quantity q = new Quantity() ; 
			if(LanguageEnum.JAVA.name().equals(bean.getLanguage())) {  // Java语言
				if(bean.getScene().equals(SceneEnum.DEV.name())) {  // 开发环境 
					q.setAmount("128Mi");
				} else if(bean.getScene().equals(SceneEnum.NORMAL.name())) {  // 通用环境 
					q.setAmount("512Mi");
				} else if(bean.getScene().equals(SceneEnum.PRO.name())) {  // 生产环境 
					q.setAmount("1024Mi");
				}
			}
			map.put("memory", q) ; 
		}
		
		return map ;
		
	}

	private List<EnvVar> initEnv() {
		List<EnvVar> envMap = new ArrayList<EnvVar>() ;

		EnvVar e1 = new EnvVar() ;
		e1.setName("SPRING_APPLICATION_NAME") ;
		e1.setValue("alinesno-cloud-initializr-admin-boot") ;

		EnvVar e2 = new EnvVar() ;
		e2.setName("SERVER_PORT") ;
		e2.setValue("8080") ;

		EnvVar e3 = new EnvVar() ;
		e3.setName("REGISTER_ADDRESS") ;
		e3.setValue("nacos://nacos.your-domain.com:23456") ;

		EnvVar e4 = new EnvVar() ;
		e4.setName("REDIS_HOST") ;
		e4.setValue("dev-redis") ;

		EnvVar e5 = new EnvVar() ;
		e5.setName("REDIS_PORT") ;
		e5.setValue("6379") ;

		EnvVar e6 = new EnvVar() ;
		e6.setName("REDIS_PASSWORD") ;
		e6.setValue("2njv2EIXmLj5DjdH") ;

		EnvVar e7 = new EnvVar() ;
		e7.setName("DATASOURCE_URL") ;
		e7.setValue("jdbc:mysql://47.119.120.221:3307/dev_alinesno_cloud_base_initial_v212?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&serverTimezone=GMT&allowPublicKeyRetrieval=true") ;

		EnvVar e8 = new EnvVar() ;
		e8.setName("DATASOURCE_HOST") ;
		e8.setValue("dev-mysql:3306") ;

		EnvVar e9 = new EnvVar() ;
		e9.setName("DATASOURCE_USERNAME") ;
		e9.setValue("root") ;

		EnvVar e10 = new EnvVar() ;
		e10.setName("DATASOURCE_PASSWORD") ;
		e10.setValue("Xinhu@1234qwer") ;

		EnvVar e11 = new EnvVar() ;
		e11.setName("JAVA_TOOL_OPTIONS") ;
		e11.setValue("-Xms128m -Xmx512m -Dspring.profiles.active=hub") ;

		EnvVar e12 = new EnvVar() ;
		e12.setName("CDN") ;
		e12.setValue("http://static.cloud.linesno.com") ;

		EnvVar e13 = new EnvVar() ;
		e13.setName("CAS_SERVICE") ;
		e13.setValue("http://v2.cas.your-domain.com:23456") ;

		EnvVar e14 = new EnvVar() ;
		e14.setName("SERVICE_URL_PREFIX") ;
		e14.setValue("http://v2.initializr.your-domain.com:23456") ;

		EnvVar e15 = new EnvVar() ;
		e15.setName("DUBBO_PROTOCOL_POT") ;
		e15.setValue("25109") ;

		envMap.add(e1) ; 
		envMap.add(e2) ; 
		envMap.add(e3) ; 
		envMap.add(e4) ; 
		envMap.add(e5) ; 
		envMap.add(e6) ; 
		envMap.add(e7) ; 
		envMap.add(e8) ; 
		envMap.add(e9) ; 
		envMap.add(e10) ; 
		envMap.add(e11) ; 
		envMap.add(e12) ; 
		envMap.add(e13) ; 
		envMap.add(e14) ; 
		envMap.add(e15) ; 
		
		return envMap ; 
	}

}
